const express = require('express');
const fetch = require('node-fetch');
const compression = require('compression');
const { HttpsProxyAgent } = require('https-proxy-agent');
const bodyParser = require('body-parser');

// 提取域名中的二级域名
function extractPrefix(domain) {
  const domainParts = domain.split('.');
  return domainParts.slice(0, domainParts.length - 2).join('.');
}

const commonRes = async (fetchHost, req, res) => {
  const tempArr = req.hostname.split('.');
  const reqHost = tempArr.slice(tempArr.length - 2).join('.')
  const reqHostPrefix = extractPrefix(req.hostname);
  // 替换url中的错误url
  let url = req.url;
  url = url.replace(new RegExp(reqHost + ':' + serverPort, "g"), targetHost)
  // 替换http为https
  url = url.replace(/http/g, 'https');
  let targetUrl = 'https://' + reqHostPrefix + '.' + targetHost + url;
  if (fetchHost) targetUrl = 'https://' + fetchHost + url;
  const parsedUrl = new URL(targetUrl);

  // Copy request headers
  const newRequestHeaders = Object.assign({}, req.headers);
  newRequestHeaders.host = parsedUrl.host;
  newRequestHeaders.origin = 'https://' + parsedUrl.host;
  newRequestHeaders.referer = 'https://' + parsedUrl.host + (req.pathname ? req.pathname : '');
  if (newRequestHeaders.cookie) {
    newRequestHeaders.cookie = newRequestHeaders.cookie.replace(new RegExp(reqHost, 'g'), targetHost)
    // console.log('reqCookie', newRequestHeaders.cookie)
    newRequestHeaders.cookie = newRequestHeaders.cookie.replace(new RegExp('Proxy__Host-', 'g'), '__Host-')
    newRequestHeaders.cookie = newRequestHeaders.cookie.replace(new RegExp('Proxy__Secure-', 'g'), '__Secure-')
  }
  // Create a new request options
  const requestOptions = {
    method: req.method,
    host: parsedUrl.host,
    path: parsedUrl.pathname + parsedUrl.search,
    headers: newRequestHeaders,
    agent: new HttpsProxyAgent(proxy)
  };
  if (!(req.method === 'GET' || req.method === 'HEAD')) {
    const reqType = req.headers['content-type']
    if (reqType && reqType.includes('json')) {
      requestOptions.body = JSON.stringify(req.body)
    } else if (reqType && reqType.match(/text|xml|javascript/)) {
      requestOptions.body = req.body
    }
    // todo 这里还需要处理form-data表单类型的请求
  }


  // Make the proxy request using fetch
  console.log('proxy', targetUrl, newRequestHeaders)
  const proxyRes = await fetch(targetUrl, requestOptions);

  // Modify response headers
  // proxyRes.headers.set('access-control-allow-origin', '*');
  proxyRes.headers.set('access-control-allow-credentials', 'true');
  proxyRes.headers.delete('content-security-policy');
  proxyRes.headers.delete('content-security-policy-report-only');
  proxyRes.headers.delete('clear-site-data');

  // Modify response body if it's text
  let responseBody = null

  // if (proxyRes.headers.get('content-type') && proxyRes.headers.get('content-type').includes('text')) {
  if (proxyRes.headers.get('content-type') && proxyRes.headers.get('content-type').match(/json|text|javascript/)) {
    // 1. 替换内容中的域名为当前请求的域名
    let contentText = await proxyRes.text();
    const re = new RegExp(targetHost, "g");
    responseBody = contentText.replace(re, reqHost + ':' + serverPort);
    // 2. 替换https为http
    const reHttps = new RegExp('https', "g");
    responseBody = responseBody.replace(reHttps, 'http');
    // 3. 替换cdn域名地址
    replace_dict.map(replace => {
      responseBody = responseBody.replace(new RegExp(replace, 'g'), replace + '.' + reqHost + ':' + serverPort)
    })
  } else {
    let arrbuffer = await proxyRes.arrayBuffer()
    responseBody = Buffer.from(arrbuffer)
  }

  // Send modified response
  const headers = proxyRes.headers.raw()
  // 'content-length' 与 'transfer-encoding: chunked'只能有一个
  // 如果 'content-encoding': 'br'，那么内容必须为br压缩，不能是纯文本
  const filterHeader = {}
  Object.keys(headers).forEach(key => {
    if (key !== 'transfer-encoding' && key !== 'content-encoding') {
      if (key === 'content-type') {
        filterHeader['content-type'] = headers['content-type'][0]
      } else if (key === 'set-cookie') {
        if (headers[key].length) {
          // 替换cookie的域名
          let ckArr = headers[key].map(cookie => cookie.replace(new RegExp(targetHost, "g"), reqHost));
          // 去除secure，允许http请求发送cookie
          ckArr = ckArr.map(cookie => cookie.replace(new RegExp("Secure;", "g"), ""));
          // 替换“__Host-”、“__Secure-”的特殊cookie
          ckArr.forEach(cookie => {
            if (cookie.startsWith('__Host-')) {
              ckArr.push(cookie.replace('__Host-', 'Proxy__Host-'))
            }
            if (cookie.startsWith('__Secure-')) {
              ckArr.push(cookie.replace('__Secure-', 'Proxy__Secure-'))
            }
            return cookie
          });
          filterHeader[key] = ckArr;
        }
      } else {
        filterHeader[key] = headers[key]
      }
    }
  })
  res.set(filterHeader);
  res.status(proxyRes.status).send(responseBody);
}


// 替换成你想镜像的站点
const targetHost = 'bing.com';
// cdn请求地址替换成代理地址，方便修改cdn响应内容的域名和cookie中的域名
const replace_dict = [
  "cdn.oaistatic.com"
]
// 代理地址
const proxy = 'http://192.168.0.135:7898';


const app = express();
// 使用 body-parser 中间件来解析 JSON 数据
app.use(bodyParser.json());
// 使用compression中间件
app.use(compression());
const serverPort = 4000;

app.use(bodyParser.text({ type: 'text/*' }));

app.all('*', async (req, res) => {
  try {
    let replaceFlag = false;
    let replaceHost = null;
    replace_dict.map(item => {
      if (req.hostname.includes(item)) {
        replaceFlag = true;
        replaceHost = item
      }
    })
    if (replaceFlag) {
      console.log('1111')
      // 处理需要替换请求的地址
      commonRes(replaceHost, req, res)
    } else {
      console.log('222')
      commonRes('', req, res)
    }
  } catch (error) {
    console.error('Error:', error);
    res.status(500).send('Internal Server Error');
  }
});

app.listen(serverPort, () => {
  console.log(`Server listening on port ${serverPort}`);
});

